import { LLMProvider } from "../../../core/llms/modelProvider";
import { imageToBase64 } from "../../../core/utils";
// import * as fs from "fs";
import * as path from "path";
import { Annotation } from "@langchain/langgraph";
import { LLMNode, baseInputVars, ILLMModelChunk, SendMessageData } from "../../../core";
import { IImageListItem } from "../../imageEditorWork/data";

export class ImageExtNode extends LLMNode {
    systemPrompt = `
    ## role
    你是「Visual Analyst Pro」，一个专业的图像内容、风格和元数据提取引擎。你的任务是以极高的准确度分析用户上传的图片，并将所有对商业宣传海报生成有价值的信息，转化为结构化的JSON数据。

    ## 核心指令：​​
    1.对用户上传的图片进行深度分析。
    2.将分析结果严格按照下方定义的JSON Schema输出。
    3.分析必须全面，涵盖视觉内容、构图、色彩、文字、风格及潜在用途。
    4.所有输出必须为​​纯JSON对象​​，无需任何额外的解释、前言或后缀。

    \`\`\`
{
    "report": {
        "subject": {
            "main": [
                "字符串数组，描述图片中最突出的主体，如人物、产品、动物等"
            ],
            "action": "字符串，描述画面中正在发生的主要动作或场景",
            "environment": "字符串，描述场景所处的环境，如室内、户外、自然、城市、工作室等"
        },
        "composition": {
            "type": "字符串，描述构图类型，如中心构图、对称构图、对角线构图、黄金分割、满版型等",
            "position": "字符串，描述关键元素（如主体）在画面中的位置",
            "bg_complexity": "字符串，评估背景复杂度，如纯色、简单、中度复杂、非常复杂"
        },
        "color": {
            "dominant": [
                "十六进制颜色代码数组，如 ['#FF0000', '#00FF00']，代表图片中最主要的2-3种颜色"
            ],
            "mood": "字符串，描述色彩传递的情绪或氛围，如活力、宁静、奢华、温暖、科技感"
        },
        "text": {
            "content": [
                "字符串数组，提取图片中所有可读的文字内容。若无则为空数组"
            ],
            "language": "字符串，标识文字的语言，如中文、英文。若无文字则为空"
        },
        "style": {
            "type": "字符串，描述图片的整体艺术或摄影风格，如极简主义、写实、复古、未来感、插画风、胶片感、3D渲染",
            "lighting": "字符串，描述光线质量，如柔和光、硬光、自然光、工作室光、戏剧性光影"
        },
        "usage": {
            "quality": "字符串，评估图片质量是否适合高清印刷，如'适合印刷'、'仅适合网络使用'",
            "industries": [
                "字符串数组，根据图片内容推测其适合的行业，如科技、美容、餐饮、教育、运动"
            ],
            "use_cases": [
                "字符串数组，推测该图片可能适合的宣传类型，如产品推广、品牌形象、活动海报、社交媒体广告"
            ]
        }
    }
}
    \`\`\`

    分析指南：​​
        ∙​​核心主体：​​ 识别最重要的视觉焦点。是产品？模特？风景？建筑？
        ∙​​构图：​​ 分析元素如何排列。主体是否居中？是否有引导线？背景是否干净，便于添加文案？
        ∙​​色彩：​​ 提取主导色，这些颜色将作为海报设计的主色调。判断色彩传递的情感。
        ∙​​文字：​​ 精确提取图片中任何现成的文字（品牌名、标语等），并注明语言。
        ∙​​风格：​​ 判断图片是真实的照片还是抽象的图形？是复古的还是现代的？这决定了海报的整体设计风格。
        ∙​​用途推测：​​ 基于图片内容，智能推断它最适合用于宣传什么类型的产品或服务。

    ​输出要求：​​
        ∙​​必须​​ 输出纯JSON格式。
        ∙​​必须​​ 完全遵守上述JSON结构。
        ∙​​必须​​ 尽最大努力填充每一个字段，即使某些字段的判断是“未知”或“不适用”。
        ∙​​禁止​​ 在JSON对象之外添加任何其他文本、评论或说明。
    `;
    inputVars = Annotation.Root({
        ...baseInputVars.spec,
        imageList: Annotation<IImageListItem[]>,
    });

    outputVars = Annotation.Root({
        imageExt: Annotation<string>,
        imageList: Annotation<IImageListItem[]>,
    });

    name = "ImageExtNode";

    protected OnModelStreamOut(chunk: ILLMModelChunk): void {
        this.OnMessage?.(this, new SendMessageData(this.inputVars.State.convID, this.name, "chat_node", chunk));
    }

    protected OnRunBegin(): void {
        this.OnMessage?.(this, new SendMessageData(this.inputVars.State.convID, this.name, "chat_node_title", { text: "解析用户上传图片..." }));
    }

    protected OnRunEnd(): void {
        this.OnMessage?.(this, new SendMessageData(this.inputVars.State.convID, this.name, "chat_node_title", { text: "完成解析用户上传图片！" }));
    }

    private async identifyImgHandle(base64: string, imgKey: string) {
        const model = LLMProvider.current.DoubaoSeed16Vision;
        model.OnStreamOut = this.OnModelStreamOut.bind(this);
        const prompts = [
            {
                role: "user",
                content: [
                    {
                        image_url: {
                            url: base64
                        },
                        type: "image_url"
                    },
                    {
                        text: this.systemPrompt,
                        type: "text"
                    }
                ]
            }
        ] as any;
        const streamOutput = await model.stream(prompts)
        for await (const chunk of streamOutput) {
        }

        this.usage.add(model.totalUsage);
        return {
            imageExt: model.lastFullResponse,
            imageKey: imgKey,
        }
    }

    async Run() {
        this.OnRunBegin();
        const plist = [];
        let uploadDir = path.join(__dirname, '../../../../uploads');
        if (process.env.USER_DIR) {
            uploadDir = path.join(process.env.USER_DIR, 'uploads');
        }
        for (let x of this.inputVars.State.imageList) {
            const imagePath = path.join(uploadDir, x.filename);
            const base64 = await imageToBase64(imagePath);
            x.base64 = base64;
            plist.push(this.identifyImgHandle(base64, x.imgKey));
        }

        const result = await Promise.all(plist) as { imageExt: string, imageKey: string }[];
        let finalImageExt = result.map(x => {
            return `
            ## ${x.imageKey}
            ${x.imageExt}
            `;
        }).join("\n\n")


        if (this.inputVars.State.imageList.length > 0) {
            this.outputVars.State.imageExt = finalImageExt;
            this.outputVars.State.imageList = this.inputVars.State.imageList;
        }
        else {
            this.outputVars.State.imageExt = "";
        }

        this.OnRunEnd();
        return this.outputVars.State;
    }
}